﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Text.RegularExpressions;

namespace craigsPack
{
    public static class Extensions
    {
        public static void AddRange(this HashSet<string> list,IEnumerable<string> array)
        {
            foreach (var item in array)
            {
                list.Add(item);
            }
        }
        /// <summary>
        /// Returns the ad title
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static string GetTitle(this HtmlNode nodes)
        {
           return nodes.FindFirstTag("a").InnerText;
        }
        /// <summary>
        /// Returns the <c>WeakDate</c> of the ad
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static WeakDate GetDatePosted(this HtmlNode nodes)
        {
            HtmlNode node =  nodes.FindFirstTag("#text");
            while (node != null)
            {
                string[] monthDay = node.InnerText.Replace("\t", "").Replace("\r", "").Replace("\n", "").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if(monthDay.Length == 3)
                   return new WeakDate(monthDay[0], monthDay[1]);
            }
            return new WeakDate();
        }
        /// <summary>
        /// Checks whether the node has more pages
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static bool HasMorePages(this HtmlNode nodes)
        {
            return nodes.FindTags("p").Count(o => o.Attributes["class"].Value == "row") != 0;
        }
        /// <summary>
        /// Returns the city from which a ad specified
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns>Returns null if no city is found</returns>
        public static string GetWeakCity(this HtmlNode nodes)
        {
            return nodes.FindTags("font").Length > 0 ? nodes.FindTags("font")[0].InnerText.Replace("(", "").Replace(")", "") : null;
        }
        /// <summary>
        /// Returns the inner link to the ad
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static Uri GetLink(this HtmlNode nodes)
        {
            HtmlNode node = nodes.FindFirstTag("a");
            if (node.Attributes["href"].Value.StartsWith("http://"))
                return new Uri(node.Attributes["href"].Value);
            else
                return null;
        }
        /// <summary>
        /// Returns the anonymized craigslist email address
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static string GetEmailAddress(this HtmlNode nodes)
        {
            return nodes.FindTags("a").Where(o => o.Attributes["href"].Value.Contains("mailto:")).ToArray()[0].Attributes["href"].Value;
        }
        /// <summary>
        /// Returns the price specified in the ad title
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <returns></returns>
        public static int GetPrice(this HtmlNode nodes)
        {
            if (nodes.Attributes["class"].Value == "row")
            {
                try
                {

                    if (nodes.InnerHtml.Contains('$'))
                    {
                        string price = nodes.InnerHtml;
                        price = price.Substring(price.IndexOf('$') + 1,price.IndexOf('<',price.IndexOf('$')) - price.IndexOf('$') - 1);
                        int result = 0;
                        if (int.TryParse(price, out result))
                            return result;
                       
                    }
                }
                catch
                {

                }
            }
            return -1;
        }
        /// <summary>
        /// Returns the first element with the specified tag name in the html document
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <param name="tag">name of tag</param>
        /// <returns></returns>
        public static HtmlNode FindFirstTag(this HtmlNode nodes,string tag)
        {
            foreach (var item in nodes.ChildNodes)
            {
                if (item.Name == tag && !item.InnerText.All(o => o == '\t' || o == '\r' || o == '\n') && !string.IsNullOrWhiteSpace(item.InnerText))
                    return item;
                else if (item.HasChildNodes)
                    FindTags(item, tag);
            }
            return null;
        }
        /// <summary>
        /// Returns all the elements with the specified tag name in the html document
        /// </summary>
        /// <param name="nodes">a html node that is of tag &lt;p class="row"&gt; html... &lt;/p&gt;</param>
        /// <param name="tag">name of tag</param>
        /// <returns></returns>
        public static HtmlNode[] FindTags(this HtmlNode nodes, string tag)
        {
            List<HtmlNode> nodes1 = new List<HtmlNode>();

            foreach (var item in nodes.ChildNodes)
            {
                if (item.Name == tag)
                    nodes1.Add(item);
                else if (item.HasChildNodes)
                    nodes1.AddRange(FindTags(item, tag));
            }
            return nodes1.ToArray();
        }
        public static HtmlNode[] FindTags(this HtmlNode nodes, string tag,Func<HtmlNode,bool> func)
        {
            List<HtmlNode> nodes1 = new List<HtmlNode>();
            
            foreach (var item in nodes.ChildNodes)
            {
                if (item.Name == tag && func.Invoke(item))
                    nodes1.Add(item);
                else if (item.HasChildNodes)
                    nodes1.AddRange(FindTags(item, tag));
            }
            return nodes1.ToArray();
        }
    }
}
